package com.iking.toolkit.util;

import com.iking.toolkit.model.Msg;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.*;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

@Component
@Slf4j
public class ImageFileUtil {

    // 格式与MIME类型映射表
    private static final Map<String, String> FORMAT_MIME_MAP = new HashMap<>();

    static {
        FORMAT_MIME_MAP.put("jpg", "image/jpeg");
        FORMAT_MIME_MAP.put("jpeg", "image/jpeg");
        FORMAT_MIME_MAP.put("png", "image/png");
        FORMAT_MIME_MAP.put("gif", "image/gif");
        FORMAT_MIME_MAP.put("bmp", "image/bmp");
        FORMAT_MIME_MAP.put("jfif", "image/jpeg"); // JFIF本质是JPEG的一种变体
    }

    // 支持的转换格式列表
    private static final String[] SUPPORTED_FORMATS = {"jpg", "jpeg", "png", "gif", "bmp",  "jfif"};



    /**
     * 通过文件头（魔术数字）识别真实文件格式
     *
     * @param fileBytes 文件字节数组
     * @return 真实格式（如"png"、"jpg"），未知格式返回null
     */
    private String getRealFormatByHeader(byte[] fileBytes) {
        if (fileBytes == null || fileBytes.length < 8) {
            return null; // 字节数不足，无法识别
        }

        // 读取文件头前8字节（十六进制字符串，大写）
        StringBuilder headerHex = new StringBuilder();
        for (int i = 0; i < Math.min(8, fileBytes.length); i++) {
            String hex = Integer.toHexString(fileBytes[i] & 0xFF);
            if (hex.length() == 1) {
                headerHex.append("0");
            }
            headerHex.append(hex);
        }
        String header = headerHex.toString().toUpperCase();

        // 匹配格式
        if (header.startsWith("FFD8FF")) { // JPG/JPEG/JFIF（均以FFD8开头）
            // 进一步区分JFIF（包含"JFIF"标识，偏移6-9字节）
            if (fileBytes.length >= 10) {
                String jfifMarker = new String(fileBytes, 6, 4);
                if ("JFIF".equals(jfifMarker)) {
                    return "jfif";
                }
            }
            return "jpg";
        } else if (header.startsWith("89504E47")) { // PNG
            return "png";
        } else if (header.startsWith("47494638")) { // GIF
            return "gif";
        } else if (header.startsWith("424D")) { // BMP
            return "bmp";
        }
        return null; // 未知格式
    }

    /**
     * 图片转图片通用方法
     *
     * @param sourceFile   源文件
     * @param targetFormat 目标格式（小写）
     */
    public Msg<MultipartFile> imageToImage(MultipartFile sourceFile, String targetFormat) {
        // 基础校验
        if (sourceFile.isEmpty()) {
            return Msg.fail("上传的图片文件为空，请重新上传");
        }

        String originalFilename = sourceFile.getOriginalFilename();
        if (originalFilename == null) {
            return Msg.fail("文件名不存在");
        }

        // 校验目标格式是否支持
        if (!isSupportedFormat(targetFormat)) {
            return Msg.fail("不支持的目标格式：" + targetFormat);
        }

        // 获取目标MIME类型
        String targetMimeType = FORMAT_MIME_MAP.get(targetFormat);
        if (targetMimeType == null) {
            return Msg.fail("未找到格式对应的MIME类型：" + targetFormat);
        }

        // 读取源文件内容到内存
        byte[] sourceBytes;
        try {
            sourceBytes = sourceFile.getBytes();
        } catch (IOException e) {
            log.error("读取源图片内容失败", e);
            return Msg.fail("读取文件失败：" + e.getMessage());
        }

        // 关键修改：通过文件头获取真实格式，而非依赖扩展名
        String realSourceFormat = getRealFormatByHeader(sourceBytes);
        if (realSourceFormat == null) {
            return Msg.fail("无法识别图片格式，请检查文件有效性");
        }
        log.debug("文件真实格式：{}，文件名扩展名：{}", realSourceFormat, getSourceFormat(originalFilename));

        // 处理转换逻辑
        File tempTargetFile = null;
        try {
            // 1. 读取源图片（使用真实格式解析）
            BufferedImage sourceImage = readImageWithFormat(sourceBytes, realSourceFormat); // 传入真实格式
            if (sourceImage == null) {
                return Msg.fail("无法解析图片内容，可能是无效的图片文件");
            }

            // 2. 处理图片格式特殊性
            BufferedImage processedImage = processImageForTargetFormat(sourceImage, targetFormat);

            // 3. 创建临时文件
            tempTargetFile = File.createTempFile("img-convert-", "." + targetFormat);
            tempTargetFile.deleteOnExit();

            // 4. 写入目标格式文件
            boolean writeSuccess = writeImageToFile(processedImage, targetFormat, tempTargetFile);
            if (!writeSuccess) {
                return Msg.fail("转换失败，不支持的目标格式或缺少对应解码器：" + targetFormat);
            }

            // 5. 验证转换结果
            if (tempTargetFile.length() == 0) {
                return Msg.fail(targetFormat + "文件生成失败，内容为空");
            }

            // 6. 封装为MultipartFile
            byte[] targetBytes = Files.readAllBytes(tempTargetFile.toPath());
            String targetFilename = buildTargetFilename(originalFilename, targetFormat);

            MultipartFile resultFile = new MockMultipartFile(
                    "file",
                    targetFilename,
                    targetMimeType,
                    targetBytes
            );

            log.info("图片转换成功：{} -> {}，大小：{} bytes",
                    originalFilename, targetFilename, resultFile.getSize());
            return Msg.sucess(resultFile);

        } catch (Exception e) {
            log.error("图片转{}失败", targetFormat, e);
            return Msg.fail("转换失败：" + e.getMessage());
        } finally {
            // 清理临时文件
            if (tempTargetFile != null && tempTargetFile.exists() && !tempTargetFile.delete()) {
                log.warn("临时文件清理失败：{}", tempTargetFile.getAbsolutePath());
            }
        }
    }

    /**
     * 所有图片格式转PDF
     */
    public Msg<MultipartFile> imageToPdf(MultipartFile imageFile) {
        // 基础校验
        if (imageFile.isEmpty()) {
            return Msg.fail("上传的图片文件为空，请重新上传");
        }

        String originalFilename = imageFile.getOriginalFilename();
        if (originalFilename == null) {
            return Msg.fail("文件名不存在");
        }

        // 读取源文件内容
        byte[] imageBytes;
        try {
            imageBytes = imageFile.getBytes();
        } catch (IOException e) {
            log.error("读取图片内容失败", e);
            return Msg.fail("读取文件失败：" + e.getMessage());
        }

        // 转换逻辑
        File tempPdfFile = null;
        try {
            // 1. 读取图片
            BufferedImage image = ImageIO.read(new ByteArrayInputStream(imageBytes));
            if (image == null) {
                return Msg.fail("无法解析图片内容，可能是无效的图片文件");
            }

            // 2. 创建PDF文档
            PDDocument document = new PDDocument();

            // 3. 计算页面尺寸（按图片比例适配A4）
            float imageWidth = image.getWidth();
            float imageHeight = image.getHeight();
            float a4Width = PDRectangle.A4.getWidth();
            float a4Height = PDRectangle.A4.getHeight();

            // 计算缩放比例
            float scale = Math.min(a4Width / imageWidth, a4Height / imageHeight);
            float scaledWidth = imageWidth * scale;
            float scaledHeight = imageHeight * scale;

            // 创建适配图片的页面
            PDPage page = new PDPage(new PDRectangle(scaledWidth, scaledHeight));
            document.addPage(page);

            // 4. 写入图片到PDF
            try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
                PDImageXObject pdImage = LosslessFactory.createFromImage(document, image);
                contentStream.drawImage(pdImage, 0, 0, scaledWidth, scaledHeight);
            }

            // 5. 保存PDF到临时文件
            tempPdfFile = File.createTempFile("img2pdf-", ".pdf");
            tempPdfFile.deleteOnExit();
            document.save(tempPdfFile);
            document.close();

            // 6. 验证PDF
            if (tempPdfFile.length() == 0) {
                return Msg.fail("PDF文件生成失败，内容为空");
            }

            // 7. 封装结果
            byte[] pdfBytes = Files.readAllBytes(tempPdfFile.toPath());
            String pdfFilename = originalFilename.substring(0, originalFilename.lastIndexOf(".")) + ".pdf";

            MultipartFile resultFile = new MockMultipartFile(
                    "file",
                    pdfFilename,
                    "application/pdf",
                    pdfBytes
            );

            log.info("图片转PDF成功：{} -> {}，大小：{} bytes",
                    originalFilename, pdfFilename, resultFile.getSize());
            return Msg.sucess(resultFile);

        } catch (Exception e) {
            log.error("图片转PDF失败", e);
            return Msg.fail("转换失败：" + e.getMessage());
        } finally {
            if (tempPdfFile != null && tempPdfFile.exists() && !tempPdfFile.delete()) {
                log.warn("PDF临时文件清理失败：{}", tempPdfFile.getAbsolutePath());
            }
        }
    }


    // ------------------------------ 辅助方法 ------------------------------

    /**
     * 读取图片（处理ICO多帧、WEBP等特殊格式）
     */
    private BufferedImage readImageWithFormat(byte[] imageBytes, String sourceFormat) throws IOException {
        try (ImageInputStream iis = ImageIO.createImageInputStream(new ByteArrayInputStream(imageBytes))) {
            Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName(sourceFormat);
            if (readers.hasNext()) {
                ImageReader reader = readers.next();
                reader.setInput(iis);
                // 处理GIF动画（取第一帧）
                if ("gif".equalsIgnoreCase(sourceFormat)) {
                    return reader.read(0);
                }
                return reader.read(0);
            }
        }
        // 通用读取方式
        return ImageIO.read(new ByteArrayInputStream(imageBytes));
    }

    /**
     * 根据目标格式处理图片（如移除透明通道、调整色彩模式）
     */
    private BufferedImage processImageForTargetFormat(BufferedImage sourceImage, String targetFormat) {
        // 1. 处理不支持透明通道的格式
        if ("jpg".equalsIgnoreCase(targetFormat) || "jpeg".equalsIgnoreCase(targetFormat)
                || "bmp".equalsIgnoreCase(targetFormat) || "jfif".equalsIgnoreCase(targetFormat)) {

            if (sourceImage.getAlphaRaster() != null) {
                // 创建RGB模式图片（白色背景）
                BufferedImage rgbImage = new BufferedImage(
                        sourceImage.getWidth(),
                        sourceImage.getHeight(),
                        "bmp".equalsIgnoreCase(targetFormat) ? BufferedImage.TYPE_3BYTE_BGR : BufferedImage.TYPE_INT_RGB
                );
                Graphics2D g = rgbImage.createGraphics();
                g.setColor(Color.WHITE);
                g.fillRect(0, 0, rgbImage.getWidth(), rgbImage.getHeight());
                g.drawImage(sourceImage, 0, 0, null);
                g.dispose();
                return rgbImage;
            }
        }

        return sourceImage;
    }

    /**
     * 写入图片到文件（处理特殊格式的写入器）
     */
    private boolean writeImageToFile(BufferedImage image, String format, File targetFile) throws IOException {
        // 特殊格式单独处理
        if ("jpg".equalsIgnoreCase(format) || "jpeg".equalsIgnoreCase(format)) {
            return writeJpegImage(image, targetFile);
        }
        // 通用格式处理
        return ImageIO.write(image, format, targetFile);
    }

    /**
     * 写入JPEG图片（控制质量）
     */
    private boolean writeJpegImage(BufferedImage image, File targetFile) throws IOException {
        Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpeg");
        if (!writers.hasNext()) {
            return false;
        }

        ImageWriter writer = writers.next();
        ImageWriteParam param = writer.getDefaultWriteParam();
        param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
        param.setCompressionQuality(0.9f); // 高质量

        try (ImageOutputStream ios = ImageIO.createImageOutputStream(targetFile)) {
            writer.setOutput(ios);
            writer.write(null, new IIOImage(image, null, null), param);
        } finally {
            writer.dispose();
        }
        return true;
    }

    /**
     * 解析源文件格式
     */
    private String getSourceFormat(String filename) {
        if (filename == null || !filename.contains(".")) {
            return "";
        }
        return filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();
    }

    /**
     * 构建目标文件名
     */
    private String buildTargetFilename(String originalFilename, String targetFormat) {
        int dotIndex = originalFilename.lastIndexOf(".");
        if (dotIndex == -1) {
            return originalFilename + "." + targetFormat;
        }
        return originalFilename.substring(0, dotIndex) + "." + targetFormat;
    }

    /**
     * 检查格式是否支持
     */
    private boolean isSupportedFormat(String format) {
        for (String supported : SUPPORTED_FORMATS) {
            if (supported.equalsIgnoreCase(format)) {
                return true;
            }
        }
        return false;
    }
}
